S Single Responsibility Principle SRP

Rapid overview

S — Single Responsibility Principle (SRP)

“A class should have one and only one reason to change.”

❌ Bad example:

public class TradeManager
{
    public void ValidateOrder(Order order) { /* ... */ }
    public void ExecuteOrder(Order order) { /* ... */ }
    public void LogOrder(Order order) { /* ... */ }
}

One class does too much: validation, execution, and logging. Changing any of these reasons breaks others.

✅ Good example:

public class OrderValidator
{
    public bool Validate(Order order) => order.Amount > 0;
}

public class OrderExecutor
{
    private readonly ITradeGateway _gateway;
    public OrderExecutor(ITradeGateway gateway) => _gateway = gateway;

    public void Execute(Order order)
    {
        _gateway.SendOrder(order);
    }
}

public class OrderLogger
{
    public void Log(Order order) => Console.WriteLine($"Executed {order.Id}");
}

👉 Each class does one thing — easier to test, maintain, and evolve.

💡 In trading systems:

  • Separate validation, risk checks, and execution.
  • Each layer can evolve independently (e.g., compliance rules, broker APIs).

---

Questions & Answers

Q: How do you recognize SRP violations?

A: When a class changes for multiple reasons—new logging needs, validation tweaks, and execution rules all touching the same file. High churn and wide unit tests are red flags.

Q: How does SRP improve deploy cadence?

A: Focused classes let teams modify one area without risk to others, reducing merge conflicts and enabling independent deployments with fewer regression tests.

Q: Can a class coordinate other classes and still obey SRP?

A: Yes, if its sole reason is orchestration. For example, OrderProcessor can call validator, risk, and executor; its responsibility is orchestration, not validation logic itself.

Q: How does SRP influence folder/project structure?

A: Group types by feature/use case, not by type (e.g., Orders/OrderValidator.cs). This keeps responsibilities cohesive and discoverable.

Q: What role do interfaces play in SRP?

A: Interfaces define focused contracts (IOrderValidator, IRiskService), ensuring implementations stay narrow and substitution-friendly.

Q: How do you refactor SRP violations safely?

A: Extract class responsibilities incrementally, add unit tests, and use DI to wire new components. Feature toggles can help decouple releases.

Q: Can modules (not just classes) violate SRP?

A: Absolutely. Services that mix API logic, data access, and scheduling also violate SRP; break them into modules or microservices with single purposes.

Q: How does SRP impact observability?

A: Focused components emit targeted metrics/logs, making it easier to pinpoint issues (e.g., validation vs execution failures).

Q: What tooling catches SRP issues?

A: Static analysis for cyclomatic complexity, architecture tests (NetArchTest), and code reviews that demand clear reasons-to-change statements.

Q: How do you communicate SRP to non-technical stakeholders?

A: Describe it as separating responsibilities like accounting vs trading—each workflow has its own owner, reducing risk when requirements change.